feat(integration): Exploit Intelligence integration#1125
Conversation
… table Add a new "Exploit Intelligence" column to the SBOM details vulnerability table that enables exploit intelligence analysis for Critical and High severity vulnerabilities. The component uses local state with mock data; real API integration is planned for a future task. - Create ExploitIntelligenceAnalysisCell component with severity gating - Non-eligible severities display "Not eligible" with tooltip - Eligible vulnerabilities show "Run analysis" button - Mock analysis returns deterministic results based on CVE identifier - Results displayed as color-coded PatternFly Labels Implements TC-4676 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Assisted-by: Claude Code
…cell - Add initialSort for CVSS descending in vulnerability table - Fix timer leak in handleRunAnalysis using useRef + useEffect cleanup - Expand analysis state model from 3 states to all 6 spec states - Replace inline color token with PatternFly Content component Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Refactor ExploitIntelligenceAnalysisCell to pure presentational component - Export ExploitIntelligenceCellState type for TC-4678 API wiring - Add View report link for completed findings with reportUrl - Fix non-eligible CVE rendering to disabled button with tooltip - Add 9 unit tests covering all states and callbacks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace mock state management with TanStack Query hooks that fetch job status from /api/v3/exploit-intelligence and submit analysis requests. Auto-polls every 10s while jobs are pending or running. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rework the ExploitIntelligenceAnalysisCell to match the updated UX mockup for SPDX multi-component analysis results: - Refactor finding type to a discriminated union with optional count and breakdown fields per variant (replaces flat componentProgress) - Show count-prefixed labels for multi-component results (e.g. "21 Vulnerable", "4 Uncertain") - Replace Popover + DescriptionList breakdown with a Tooltip showing plain-text lines for non-zero categories - Switch "Request Analysis" button from link+icon to secondary variant - Render "In progress" as a Label with inline Spinner icon - Add "Not vulnerable" filled label variant - Add failed-state tooltip message - Update jobToState() to produce count/breakdown from backend component counts on completed multi-component jobs - Update tests for new type shapes and rendering Implements: TC-4676 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reviewer's GuideAdds Exploit Intelligence integration to the SBOM vulnerabilities table, including a new analysis column wired to a backend EI API, React Query hooks for job polling and submission, a reusable cell component with status/tooltip/report link behavior, severity-based eligibility rules, notifications on submission failure, and comprehensive unit tests for state mapping and UI rendering. Sequence diagram for Exploit Intelligence analysis request and job pollingsequenceDiagram
actor User
participant VulnerabilitiesBySbom
participant ExploitIntelligenceAnalysisCell
participant useSubmitExploitAnalysisMutation
participant ExploitIntelligenceAPI
participant useFetchExploitIntelligenceJobs
User->>ExploitIntelligenceAnalysisCell: click Request Analysis
ExploitIntelligenceAnalysisCell->>VulnerabilitiesBySbom: onRequestAnalysis(vulnerabilityIdentifier)
VulnerabilitiesBySbom->>useSubmitExploitAnalysisMutation: mutate({ sbom_id, vulnerability_id })
useSubmitExploitAnalysisMutation->>ExploitIntelligenceAPI: POST /api/v3/exploit-intelligence/analyze
ExploitIntelligenceAPI-->>useSubmitExploitAnalysisMutation: SubmitAnalysisResponse
useSubmitExploitAnalysisMutation->>useFetchExploitIntelligenceJobs: invalidateQueries([ExploitIntelligenceQueryKey, "jobs", sbom_id])
loop while hasActiveJobs(jobs)
useFetchExploitIntelligenceJobs->>ExploitIntelligenceAPI: GET /api/v3/exploit-intelligence/jobs?sbom_id
ExploitIntelligenceAPI-->>useFetchExploitIntelligenceJobs: JobsListResponse
useFetchExploitIntelligenceJobs->>useFetchExploitIntelligenceJobs: buildStateMap(jobs)
useFetchExploitIntelligenceJobs-->>VulnerabilitiesBySbom: stateMap
VulnerabilitiesBySbom-->>ExploitIntelligenceAnalysisCell: state
end
useSubmitExploitAnalysisMutation-->>VulnerabilitiesBySbom: onError
VulnerabilitiesBySbom->>NotificationsContext: pushNotification({ title, variant: "danger" })
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1125 +/- ##
==========================================
+ Coverage 51.48% 53.97% +2.48%
==========================================
Files 275 272 -3
Lines 5988 6044 +56
Branches 1853 1920 +67
==========================================
+ Hits 3083 3262 +179
+ Misses 2593 2476 -117
+ Partials 312 306 -6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The initialSort override changed the vulnerability table default from Id ascending to CVSS descending, breaking existing e2e sort tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
carlosthe19916
left a comment
There was a problem hiding this comment.
@Strum355 I assume this PR is not a draft as @ptomanRH asked me to review it.
Please remove the draft status.
I added only some code polishing review focused only on the code. I can't actually test it as I assume it will require an instance of ExploitIQ so I'll trust you and your judgment to assess on whether or not the requirement is covered.
| export const useFetchExploitIntelligenceJobs = (sbomId: string | undefined) => { | ||
| const { data, isLoading, error } = useQuery({ | ||
| queryKey: [ExploitIntelligenceQueryKey, "jobs", sbomId], | ||
| queryFn: () => | ||
| axios.get<JobsListResponse>(`${EI_API}/jobs`, { | ||
| params: { sbom_id: sbomId, limit: 1000 }, | ||
| }), | ||
| enabled: !!sbomId, | ||
| refetchInterval: (query) => { | ||
| const items = query.state.data?.data?.items; | ||
| if (items && hasActiveJobs(items)) { | ||
| return POLLING_INTERVAL; | ||
| } | ||
| return false; | ||
| }, | ||
| }); | ||
|
|
||
| const jobs = data?.data?.items ?? []; | ||
|
|
||
| return { | ||
| jobs, | ||
| stateMap: buildStateMap(jobs), | ||
| isFetching: isLoading, | ||
| fetchError: error as AxiosError | null, | ||
| hasActiveJobs: hasActiveJobs(jobs), | ||
| }; | ||
| }; | ||
|
|
||
| export const useSubmitExploitAnalysisMutation = () => { | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| return useMutation({ | ||
| mutationFn: (params: SubmitAnalysisRequest) => | ||
| axios.post<SubmitAnalysisResponse>(`${EI_API}/analyze`, params), | ||
| onSuccess: async (_data, variables) => { | ||
| await queryClient.invalidateQueries({ | ||
| queryKey: [ExploitIntelligenceQueryKey, "jobs", variables.sbom_id], | ||
| }); | ||
| }, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
This block of code is the only one that should be in this file, the rest does not belong to the queries directory. Let's keep the queries clean and avoid heavy data logic there, let the caller of the functions deal with data transformation
| @@ -0,0 +1,343 @@ | |||
| import { | |||
There was a problem hiding this comment.
Not saying we don't need tests, but I find very difficult to read this file. I don't understand it, if you understand it it is fine, I won't object to it. I'd only ask you to confirm you understand the code in this test.
| .exploit-intelligence-in-progress-label .pf-v6-c-label__icon .pf-v6-c-spinner { | ||
| --pf-v6-c-spinner--Color: currentColor; | ||
| } |
There was a problem hiding this comment.
Let's avoid any custom .css. Use default patternfly components and default styles.
Using custom css or style is the last resource. It is acceptable not to comply with the mockups in order to keep Patternfly defaults. We can always push back on the mockups if they are not aligned with detault Patternfly styles
|
|
||
| return useMutation({ | ||
| mutationFn: (params: SubmitAnalysisRequest) => | ||
| axios.post<SubmitAnalysisResponse>(`${EI_API}/analyze`, params), |
There was a problem hiding this comment.
do not use axios, unless there is a reason we should use the auto generated openapi typescript client
| const ELIGIBLE_SEVERITIES: ReadonlySet<ExtendedSeverity> = new Set([ | ||
| "critical", | ||
| "high", | ||
| "medium", | ||
| "moderate", | ||
| "low", | ||
| "none", | ||
| "unknown", | ||
| ]); |
There was a problem hiding this comment.
Not sure what was the objective of ELIGIBLE_SEVERITIES, but if the idea is to reuse the severities we already have in the repository you can do:
export const extendedSeverityValues = Object.keys(
severityList,
) as ExtendedSeverity[];
Summary
Adds "Exploit Intelligence" integration support into the trustify UI. Based on the mockups by Meredith found here: https://meredithrenda.github.io/trustify-ui/sboms/a1b2c3d4-0001-4000-8000-000000000001?sd%3AactiveTab=vulnerabilities, adds the "Exploit Intelligence Analysis" column with "Request Analysis" button, analysis results cell & link to report, as well as the trustify API wiring for this.
TPA backend implementation found at the following branch: https://github.com/guacsec/trustify/compare/main...Strum355:trustify:TC-4677?expand=1
Related Issues
https://redhat.atlassian.net/browse/TC-4676 and https://redhat.atlassian.net/browse/TC-4678
Type of Change
Testing
npm test)npm run lint)Screenshots
TODO: will add later
Summary by Sourcery
Integrate exploit intelligence analysis into the SBOM vulnerabilities view, including UI, state mapping, and API wiring.
New Features:
Enhancements:
Tests: